package com.zzl.bonds.ticket.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.IoUtils;
import com.zzl.apidoc.annotation.ApidocController;
import com.zzl.apidoc.annotation.ApidocOperation;
import com.zzl.apidoc.annotation.ApidocParam;
import com.zzl.bonds.ticket.constant.status.HandStatusEnum;
import com.zzl.bonds.ticket.dto.ApUserShowInfo;
import com.zzl.bonds.ticket.dto.StatisticsDataDto;
import com.zzl.bonds.ticket.dto.TicketOpenAddDto;
import com.zzl.bonds.ticket.dto.feign.ApprovalSubmitDto;
import com.zzl.bonds.ticket.dto.ticketopen.*;
import com.zzl.bonds.ticket.entity.TicketOpenEntity;
import com.zzl.bonds.ticket.feign.FileCenterFeign;
import com.zzl.bonds.ticket.service.FileService;
import com.zzl.bonds.ticket.service.TicketOpenService;
import com.zzl.general.common.apidoc.annotation.ApidocParamsPage;
import com.zzl.general.common.apidoc.annotation.ApidocResultKeyValR;
import com.zzl.general.common.apidoc.annotation.ApidocReturnPage;
import com.zzl.general.common.apidoc.annotation.ApidocReturnR;
import com.zzl.general.common.apidoc.constants.ResultTypeInR;
import com.zzl.general.common.ctrl.WebBaseCtrl;
import com.zzl.general.common.exception.SysException;
import com.zzl.general.common.utils.LogUtils;
import com.zzl.general.common.utils.PageUtils;
import com.zzl.general.common.utils.Result;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zzl.bonds.ticket.constant.FileBucketTypeConstant.FILE_BUCKET_OPEN_RELATED_FILE;

/**
 * 开立申请表
 *
 * @author sunpp
 * @date 2022-02-16 14:04:05
 */
@ApidocController("3开单/开单签收接口")
@RestController
@SuppressWarnings("javadoc")
@RequestMapping("bondsticket/ticketopen")
@Slf4j
public class TicketOpenController extends WebBaseCtrl {
    @SuppressWarnings("all")
    @Autowired
    private TicketOpenService ticketOpenService;

    @SuppressWarnings("all")
    @Autowired
    private FileService fileService;

    @Autowired
    private FileCenterFeign fileCenterFeign;

    /**
     * 核心企业-概况
     */
    @GetMapping("/repayPlan")
    @ApidocOperation(description = "1核心企业概况-还款计划", operationId = "/bondsticket/ticket/repayPlan")
    @ApidocReturnPage(genericTypeClass = TicketOpenEntity.class)
    public Result repayPlan(@ApidocParamsPage(name = "params") @RequestParam Map<String, Object> params) {
        try {
            return Result.ok().page(ticketOpenService.repayPlan(params, this.getUser()));
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    /**
     * 开立保存
     */
    @PostMapping("/save")
    @ApidocOperation(description = "1凭证开具", operationId = "aa/ticket/ticketopen/save")
    @ApidocReturnR
    public Result save(@ApidocParam(name = "保存的开立申请表对象值", required = true) @Validated @RequestBody TicketOpenAddDto openAddDto) {
        try {
            return Result.ok().put("data", ticketOpenService.saveTicketOpen(openAddDto, this.getUser()));
        } catch (SysException e) {
            LogUtils.logSysException(log, e);
            return Result.error(e.getMsg());
        }
    }

    /**
     * 开立相关附件上传
     *
     * @param file 对象
     */
    @PostMapping("/uploadFile")
    @ApidocOperation(description = "开立相关附件上传", operationId = "aa/ticket/ticketopen/uploadFile")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", valueClass = String.class)
    })
    public Result upLoadFile(@ApidocParam(name = "file", description = "文件") @NotNull MultipartFile file) {
        try {
            log.info("开立相关附件上传{}", file.getOriginalFilename());
            String objId = fileService.upLoadFile(file, FILE_BUCKET_OPEN_RELATED_FILE.getKey());
            return Result.ok().data(objId);
        } catch (SysException e) {
            LogUtils.logSysException(log, e);
            return Result.error(e.getMsg());
        }
    }

    @PostMapping("/uploadInvoiceFile")
    @ApidocOperation(description = "上传发票", operationId = "aa/ticket/ticketopen/uploadFile")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", valueClass = InvoiceResult.class)
    })
    public Result uploadInvoiceFile(@ApidocParam(name = "file", description = "文件") @NotNull MultipartFile file) {
        try {
            log.info("上传发票{}", file.getOriginalFilename());
            return Result.ok().data(fileService.uploadInvoiceFile(file));
        } catch (SysException e) {
            LogUtils.logSysException(log, e);
            return Result.error(e.getMsg());
        }
    }

    @ApidocOperation(description = "1开立相关附件预览文件", operationId = "aa/ticket/ticketopen/previewFile")
    @ApidocReturnR
    @GetMapping("/allowAuth/previewFile/{objId}")
    public void previewFile(@ApidocParam(name = "response", description = "response") HttpServletResponse response
            , @ApidocParam(name = "objId", description = "文件唯一标识")
                            @PathVariable("objId") String objId) {
        Response responseImg = fileCenterFeign.previewFileNoAuth(objId, FILE_BUCKET_OPEN_RELATED_FILE.getKey());
        try {
            IoUtils.copy(responseImg.body().asInputStream(), response.getOutputStream());
            response.setCharacterEncoding("UTF-8");
            // 2.设置文件头：预览设置，如果是浏览器可以识别的文件
            List<String> collect = new ArrayList<>(responseImg.headers().get("Content-Disposition"));
            if (!CollectionUtils.isEmpty(collect)) {
                response.setHeader("Content-Disposition", collect.get(0));
            }
        } catch (IOException e) {
            log.error("文件预览异常");
        }
    }

    @ApidocOperation(description = " 1开立相关附件文件下载", operationId = "/downLoadFile/objId/r4/1")
    @ApidocReturnR
    @GetMapping("/allowAuth/downLoadFile/{objId}")
    public void allowAuthDownLoadFileOrd(HttpServletResponse response
            , @ApidocParam(name = "objId", description = "文件唯一标识") @PathVariable("objId") String objId) {
        Response responseImg = fileCenterFeign.downloadFileMongoAllowAuth(objId, FILE_BUCKET_OPEN_RELATED_FILE.getKey());
        try {
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            // 设置文件头：最后一个参数是设置下载文件名
            response.setHeader("Content-Disposition", responseImg.headers().get("Content-Disposition").stream().collect(Collectors.toList()).get(0));
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            IoUtils.copy(responseImg.body().asInputStream(), response.getOutputStream());

        } catch (IOException e) {
            log.error("文件下载异常");
        }
    }

    /**
     * 获取开立页面处理状态枚举值
     */
    @GetMapping("/handStatus")
    @ApidocOperation(description = "1获取开立页面处理状态枚举值", operationId = "aa/ticket/ticketopen/handStatus")
    @ApidocReturnR
    public Result getHandStatus() {
        return Result.ok().put("list", HandStatusEnum.getKvList(1));
    }


    /**
     * 分页查询开立申请凭证
     */
    @GetMapping("/list")
    @ApidocOperation(description = "1分页查询开立列表", operationId = "aa/ticket/ticketopen/list")
    @ApidocReturnPage(genericTypeClass = TicketOpenPage.class)
    public Result list(@ApidocParamsPage(name = "params", keyName = {
            "ticketNo"
            , "receiveEnterpriseName"
            , "openEnterpriseId"
            , "ticketOpenStartTime"
            , "ticketOpenEndTime"
            , "startAmount"
            , "endAmount"
            , "handStatus"
            , "page"
            , "order"
    }
            , keyDescription = {
            "凭证编号"
            , "收单企业"
            , "出单企业"
            , "开单开始日期"
            , "开单结束日期"
            , "开始金额"
            , "结束金额"
            , "处理状态，见接口与原型 依次 1,2,3,4,必穿，默认全部 "
            , "排序类型：create_time（默认）、invoice_time：开单日期、cash_time：到期日期，ticket_amount：凭证金额"
            , "排序方式：desc 降序（默认）asc 升序"})
                       @RequestParam Map<String, Object> params) {
        try {
            PageUtils page = ticketOpenService.queryPage(params, this.getUser());
            return Result.ok().put("page", page);
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    /**
     * 复核相关接口
     */

    @ApidocOperation(description = "1开单复核列表", operationId = "ticket/ticketopen/checkList")
    @ApidocReturnPage(genericTypeClass = TicketOpenCheckPage.class)
    @GetMapping("/checkList")
    public Result getCheckList(@ApidocParamsPage(name = "params", keyName = {
            "ticketNo"
            , "receiveEnterpriseName"
            , "openEnterpriseId"
            , "startAmount"
            , "endAmount"
            , "ticketOpenStartTime"
            , "ticketOpenEndTime"
            , "page"
            , "order"
    }
            , keyDescription = {
            "凭证编号"
            , "收单企业id"
            , "出单企业id"
            , "开始金额"
            , "结束金额"
            , "开单开始日期"
            , "开单结束日期"
            , "排序类型：create_time（默认）、invoice_time：开单日期、cash_time：到期日期，ticket_amount：凭证金额"
            , "排序方式：desc 降序（默认）asc 升序"})
                               @RequestParam Map<String, Object> params) {
        try {
            PageUtils page = ticketOpenService.queryOpenChekPage(params, this.getUser());
            return Result.ok().put("page", page);
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @GetMapping("/getOpenData")
    @ApidocOperation(description = "1开单页面的三个统计数量", operationId = "ticket/ticketopen/getOpenData")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", genericTypeClass = StatisticsDataDto.class)
    })
    public Result getTodayOpenStatistics() {
        return Result.ok().put("data", ticketOpenService.getOpenData(this.getUser()));
    }

    @GetMapping("/cancelOpenTicket/{id}")
    @ApidocOperation(description = "1撤销开单", operationId = "/ticket/ticketopen/cancelOpenTicket")
    @ApidocReturnR
    public Result cancelOpenTicket(@ApidocParam(name = "id", description = "开单id", required = true) @PathVariable("id") String id) {
        try {
            ticketOpenService.cancelOpenTicket(id, this.getUser());
            return Result.ok();
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @GetMapping("/reapplyOpenTicket/{id}")
    @ApidocOperation(description = "1重新申请", operationId = "/ticket/ticketopen/reapplyOpenTicket")
    @ApidocReturnR
    public Result reapplyOpenTicket(@ApidocParam(name = "id", description = "开单id", required = true) @PathVariable("id") String id) {
        try {
            ticketOpenService.reapplyOpenTicket(id, this.getUser());
            return Result.ok();
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    /**
     * 信息
     */
    @GetMapping("/info/{id}")
    @ApidocOperation(description = "1开立的详情信息", operationId = "/ticket/ticketopen/info")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", valueClass = OpenDetailDto.class)
    })
    public Result info(@ApidocParam(name = "id", description = "开立申请表id", required = true) @PathVariable("id") String id) {
        try {
            return Result.ok().put("data", ticketOpenService.getOpenDetail(id, this.getUser()));
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @GetMapping("/getOpenProcessProgress/{id}")
    @ApidocOperation(description = "1流程进度", operationId = "/ticket/getOpenProcessProgress/info")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "list", valueClass = ApUserShowInfo.class)
    })
    public Result getOpenProcessProgress(@ApidocParam(name = "id", description = "开立申请表id", required = true) @PathVariable("id") String id) {
        try {
            return Result.ok().put("list", ticketOpenService.getOpenProcessProgress(id));
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    /**
     * 凭证复核详情
     */
    @GetMapping("/openTicketCheckInfo/{id}")
    @ApidocOperation(description = "1复核详情", operationId = "/ticket/ticketopen/openTicketCheckInfo")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", valueClass = OpenTicketCheckDetailDto.class)
    })
    public Result getOpenTicketCheckInfo(@ApidocParam(name = "id", description = "开立申请表id", required = true) @PathVariable("id") String id) {
        try {
            return Result.ok().put("data", ticketOpenService.getOpenTicketCheckDetailDto(id, this.getUser()));
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @PostMapping("/openTicketCheckSubmit")
    @ApidocOperation(description = "1开立复核提交", operationId = "/ticket/ticketopen/openTicketCheckSubmit")
    @ApidocReturnR
    public Result openTicketCheckSubmit(@ApidocParam(name = "开立复核提交", required = true) @Validated @RequestBody ApprovalSubmitDto checkSubmit) {
        try {
            log.info("开立复核提交{}", JSON.toJSONString(checkSubmit));
            ticketOpenService.openTicketCheckSubmit(checkSubmit, this.getUser());
            return Result.ok();
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    /**
     * 开立签收 相关接口
     */
    @GetMapping("/signList")
    @ApidocOperation(description = "开单签收--签收列表", operationId = "/ticket/ticketopen/signList")
    @ApidocReturnPage(genericTypeClass = TicketOpenSignPage.class)
    public Result signList(@ApidocParamsPage(name = "params", keyName = {
            "ticketNo"
            , "openEnterpriseId"
            , "ticketOpenStartTime"
            , "ticketOpenEndTime"
            , "startAmount"
            , "endAmount"
            , "page"
            , "order"
    }
            , keyDescription = {
            "凭证编号"
            , "开单企业"
            , "开单开始日期"
            , "开单结束日期"
            , "开始金额"
            , "结束金额"
            , "排序类型：create_time（默认）、invoice_time：开单日期、cash_time：到期日期，ticket_amount：凭证金额"
            , "排序方式：desc 降序（默认）asc 升序"})
                           @RequestParam Map<String, Object> params) {
        try {
            PageUtils page = ticketOpenService.queryOpenSignPage(params, this.getUser());
            return Result.ok().put("page", page);
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @GetMapping("/getOpenSignData")
    @ApidocOperation(description = "开单签收页面的三个统计数量", operationId = "ticket/ticketopen/getOpenSignData/1")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", genericTypeClass = StatisticsDataDto.class)
    })
    public Result getTodayOpenSignStatistics() {
        return Result.ok().put("data", ticketOpenService.getOpenSignData(this.getUser()));
    }

    /**
     * 信息
     */
    @GetMapping("/openTicketInfo/{id}")
    @ApidocOperation(description = "开立签收--详情", operationId = "/ticket/ticketopen/openTicketInfo")
    @ApidocReturnR(otherkv = {
            @ApidocResultKeyValR(resultType = ResultTypeInR.TYPE_OBJECT, key = "data", valueClass = OpenDetailDto.class)
    })
    public Result getOpenTicketInfo(@ApidocParam(name = "开立申请表id", required = true) @PathVariable("id") String id) {
        try {
            return Result.ok().put("data", ticketOpenService.getTicketOpenSignDetail(id, this.getUser()));
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }

    @PostMapping("/openTicketSignSubmit")
    @ApidocOperation(description = "开立签收--签收结果提交", operationId = "/ticket/ticketopen/openTicketSignSubmit")
    @ApidocReturnR
    public Result openTicketSignSubmit(@ApidocParam(name = "开立签收提交", required = true) @Validated @RequestBody ApprovalSubmitDto checkSubmit) {
        try {
            ticketOpenService.openTicketSignSubmit(checkSubmit, this.getUser());
            return Result.ok();
        } catch (SysException e) {
            return Result.error(e.getMsg());
        }
    }


}
